#include "StdAfx.h"
#include "../Engine/UnitAFV.hpp"
#include "..\engine\UnitManager.hpp"

namespace he
{
	UnitManager::UnitManager(boost::filesystem::path const &WrkPath)
		: m_WrkPath(WrkPath), m_WeaponManager(m_WrkPath)
	{
	}

	UnitPtr_t UnitManager::load_afv_unit(std::string const &Side, std::string const &UnitName)
	{
		boost::filesystem::path const full_path = m_WrkPath/"data"/Side/"units"/"afv"/(UnitName + ".xml");
		// If file doesn't exist
		if(!boost::filesystem::exists(full_path))
			throw std::runtime_error("Unit file '" + full_path.string() + "' not found.");
		// Get the file size
		unsigned long const file_size = static_cast<unsigned long>(boost::filesystem::file_size(full_path));
		// Get the last modification date
		std::time_t const last_modification = boost::filesystem::last_write_time(full_path);
		// Unit already loaded
		if(m_UnitMap.count(UnitName) == 1)
		{
			// Get the filter iterator
			UnitMap_t::iterator it = m_UnitMap.find(UnitName);
			// If file wasn't changed, return the existing unit
			if(it->second.get<0>() == file_size && it->second.get<1>() == last_modification)
				return it->second.get<2>();

		}
		// Open file
		std::ifstream unit_file(full_path.string().c_str());
		// Read the content of file
		std::ostringstream file_content;
		file_content << unit_file.rdbuf();
		// Get the string
		std::string const content_string = file_content.str();
		boost::scoped_array<char> p_array(new char[content_string.size() + 1]);
		strcpy(p_array.get(), content_string.c_str());
		// Parse file
		rapidxml::xml_document<> doc;
		doc.parse<0>(p_array.get());
		// Get the root node
		rapidxml::xml_node<> *p_root = doc.first_node();
		// Get the <afv>
		rapidxml::xml_node<> *p_afv_node = p_root->first_node("afv");
		// Create unit
		boost::shared_ptr<UnitAFV> p_unit(new UnitAFV(p_root->first_attribute("name")->value(), static_cast<unsigned short>(Convert::to_uint32(p_afv_node->first_attribute("onroad")->value())),
			static_cast<unsigned short>(Convert::to_uint32(p_afv_node->first_attribute("offroad")->value()))));
		for(rapidxml::xml_node<> *p_node = p_afv_node->first_node(); p_node != nullptr; p_node = p_node->next_sibling())
		{
			// Tag name
			std::string const tag_name = p_node->name();
			// Armor
			if(tag_name == "armor")
			{
				for(rapidxml::xml_node<> *p_node_armor = p_node->first_node(); p_node_armor != nullptr; p_node_armor = p_node_armor->next_sibling())
				{
					// Armor tag name
					std::string const armor_node_name = p_node_armor->name();
					// Get all attributes
					for(rapidxml::xml_attribute<> *p_armor_attr = p_node_armor->first_attribute(); p_armor_attr != nullptr; p_armor_attr = p_armor_attr->next_attribute())
					{
						// Armor position attribute name
						std::string const armor_attr_name = p_armor_attr->name();
						// Armor position enum
						UnitAFV::ArmorLocation armor_location;
						if(armor_attr_name == "front")
							armor_location = UnitAFV::AL_FRONT;
						else if(armor_attr_name == "side")
							armor_location = UnitAFV::AL_SIDE;
						else if(armor_attr_name == "rear")
							armor_location = UnitAFV::AL_REAR;
						else if(armor_attr_name == "top_bottom")
							armor_location = UnitAFV::AL_TOP_BOTTOM;
						else
							throw std::runtime_error("Unknown attribute in armor location '" + armor_attr_name + "'");
						// Value of attribute
						std::string const attr_value = p_armor_attr->value();
						// Thickness
						unsigned short const thickness = static_cast<unsigned short>(Convert::to_uint32(attr_value.substr(0, attr_value.find('/')).c_str()));
						unsigned short const angle = static_cast<unsigned short>(Convert::to_uint32(attr_value.substr(attr_value.find('/') + 1, attr_value.size()).c_str()));
						// Superstructure
						if(armor_node_name == "superstructure")
							p_unit->set_superstructure_armor(armor_location, thickness, angle);
						// Hull
						else if(armor_node_name == "hull")
							p_unit->set_hull_armor(armor_location, thickness, angle);
					}
				}
			}
			// Weapons
			else if(tag_name == "weapons")
			{
				for(rapidxml::xml_node<> *p_weapon_node = p_node->first_node(); p_weapon_node != nullptr; p_weapon_node = p_weapon_node->next_sibling())
				{
				}
			}
			// Unknown tag
			else
				throw std::runtime_error("Unknown tag '" + tag_name + "' while parsing AFV unit.");
		}

		return p_unit;
	}
} /*he*/